#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "config.h"
#include "dllist.h"
#include "log.h"
#include "mailmsg.h"
#include "report.h"
#include "snmpapi.h"
#include "utils.h"

#define DEFAULT_FRUNKD_HTML_OUTPUT_FILE "frunkd.html"
#define DEFAULT_FRUNKD_NEW_HTML_OUTPUT_FILE \
		DEFAULT_FRUNKD_HTML_OUTPUT_FILE ".new"

#define REPORT_INTF_DOWN       1
#define REPORT_INTF_STILL_DOWN 2
#define REPORT_INTF_UP         3

static void
ReportInterfaceStatus_Email(PCONFIG_DATA pcd,
                            PDEVICE pdev, PINTERFACE pif, int status)
{
  FILE *fp=Mail_Open();
  char *pstrStatus;
  char *buffer;
  int timedown;

  if(pif->pstrTitle)
  {
    fprintf(fp, "%s: ", pif->pstrTitle);
  }

  switch(status)
  {
    case REPORT_INTF_DOWN:
      pstrStatus="DOWN";
      fprintf(fp, "%s@%s is down.\n\n%s\n", pif->pstrDescr,
              pdev->pstrAddress, pif->pstrComment);
      break;
    case REPORT_INTF_STILL_DOWN:
      pstrStatus="STILL DOWN";
      timedown=(int)(pif->timeLastPolled-pif->timeWhenWentDown);
      fprintf(fp, "%s@%s is still not up after %s.\n\n%s\n",
              pif->pstrDescr, pdev->pstrAddress,
              Computer2HumanTime(timedown), pif->pstrComment);
      break;
    case REPORT_INTF_UP:
      pstrStatus="UP";
      timedown=(int)(pif->timeLastPolled-pif->timeWhenWentDown);
      fprintf(fp, "%s@%s is up. Was not up for %s.\n\n%s\n",
              pif->pstrDescr, pdev->pstrAddress,
              Computer2HumanTime(timedown), pif->pstrComment);
      break;
    default:
      Logf(FRUNK_LOG_ERR, "ReportInterfaceStatus_Email: unknown status.");
      return;
  }

  if(pif->pstrURL)
  {
    fprintf(fp, "\nMore info available at the following URL:\n%s\n",
            pif->pstrURL);
  }

  fprintf(fp, "\n-- \nReport automatically generated by Frunk v%s\n",
          VERSION_FRUNKD);

  if(pif->pstrTitle)
  {
    MessageFormat(&buffer, "[Frunk] %s: %s", pstrStatus, pif->pstrTitle);
  }
  else
  {
    MessageFormat(&buffer, "[Frunk] %s: %s@%s",
                  pstrStatus, pif->pstrDescr, pdev->pstrAddress);
  }


  Mail_Send(fp, pcd->pstrMailEventsFrom, pcd->pstrMailEventsTo, buffer);

  free(buffer);

  Mail_Close(fp);
}

static void
CheckInterfaceStatus(PCONFIG_DATA pcd, PDEVICE pdev, PINTERFACE pif)
{
  if(pif->nLastOperStatus==SNMP_IFSTATUS_UP)
  {
    if(pif->nPrevOperStatus!=SNMP_IFSTATUS_UP)
    {
      pif->nPrevOperStatus=SNMP_IFSTATUS_UP;
      ReportInterfaceStatus_Email(pcd, pdev, pif, REPORT_INTF_UP);
    }
  }
  else
  {
    if(pif->nPrevOperStatus==SNMP_IFSTATUS_UP)
    {
      pif->nPrevOperStatus=pif->nLastOperStatus;
      pif->timeWhenWentDown=pif->timeLastPolled;
      pif->timeElapsedToReminder=pcd->nMinReminderTime;
      ReportInterfaceStatus_Email(pcd, pdev, pif, REPORT_INTF_DOWN);
    }
    else /* Interface is not up */
    {
      time_t timeDown=pif->timeLastPolled-pif->timeWhenWentDown;

      if(timeDown>=pif->timeElapsedToReminder)
      {
        time_t timeAddToReminderInterval;

        timeAddToReminderInterval=
          pif->timeElapsedToReminder+pcd->nMinReminderTime;
        if(timeAddToReminderInterval>pcd->nMaxReminderTime)
        {
          timeAddToReminderInterval=pcd->nMaxReminderTime;
        }
        pif->timeElapsedToReminder+=timeAddToReminderInterval;
        ReportInterfaceStatus_Email(pcd, pdev, pif, REPORT_INTF_STILL_DOWN);
      }
    }
  }
}

void
ReportEvents(PCONFIG_DATA pcd)
{
  PDLLELEM pedev;
  FILE *fpHTML=NULL;
  int nNumIfsDown=0;

  if(pcd->bHTMLOutput)
  {
    if(!(fpHTML=fopen(DEFAULT_FRUNKD_NEW_HTML_OUTPUT_FILE, "w")))
    {
      Logf(FRUNK_LOG_ERR, "Could not open '%s' for HTML output.",
           DEFAULT_FRUNKD_NEW_HTML_OUTPUT_FILE);
    }
    else
    {
      time_t timeNow=time(NULL);
      time_t timeExpires=timeNow+pcd->nSleepInterval;
      char *pstrTimeNow=ctime(&timeNow);
      struct tm *ptmExpires;
      char strExpires[64];

      ptmExpires=gmtime(&timeExpires);
      strftime(strExpires, sizeof(strExpires),
               "%a, %d %b %Y %H:%M:%S GMT", ptmExpires);
      fprintf(fpHTML, "<!DOCTYPE html PUBLIC "
		      "\"-//W3C//DTD HTML 4.01 Transitional//EN\" "
		      "\"http://www.w3.org/TR/html4/loose.dtd\">\n");
      fprintf(fpHTML, "<html>\n<head>\n");
      fprintf(fpHTML, "<title>Frunk - Network Monitoring System</title>\n");
      fprintf(fpHTML, "<meta http-equiv=\"Refresh\" content=\"%d\">\n",
              pcd->nSleepInterval<=600 ? 60 : pcd->nSleepInterval/10);
      fprintf(fpHTML, "<meta http-equiv=\"Expires\" content=\"%s\">\n",
              strExpires);
      fprintf(fpHTML, "</head>\n<body>\n");
      fprintf(fpHTML, "<h1>Frunk - Network Monitoring System</h1>\n");
      pstrTimeNow[strlen(pstrTimeNow)-1]='\0';
      fprintf(fpHTML, "<h3>On %s, ", pstrTimeNow);
    }
  }

  pedev=DLL_GetHeadElem(&pcd->dllDevices);
  while(pedev)
  {
    PDLLELEM pdllElemIfs;
    PDEVICE pdev;

    pdev=DLL_GetNextElem(&pedev);
    pdllElemIfs=DLL_GetHeadElem(&pdev->dllInterfaces);
    while(pdllElemIfs)
    {
      PINTERFACE pif=DLL_GetNextElem(&pdllElemIfs);

      CheckInterfaceStatus(pcd, pdev, pif);

      if(fpHTML)
      {
        /* Look for interfaces down and create HTML page */
        if(pif->nLastOperStatus!=SNMP_IFSTATUS_UP)
        {
          int timedown=(int)(pif->timeLastPolled-pif->timeWhenWentDown);
          const char *pstrTimeDown=Computer2HumanTime(timedown);

          if(!nNumIfsDown)
          {
            fprintf(fpHTML, "the following interfaces were down:</h3>\n");
          }
          ++nNumIfsDown;

          fprintf(fpHTML, "<p>");

          if(pif->pstrURL)
          {
            fprintf(fpHTML, "<a href=\"%s\" target=\"_new\">%s@%s</a> ",
                    pif->pstrURL, pif->pstrDescr, pdev->pstrAddress);
          }

          if(pif->pstrTitle)
          {
            fprintf(fpHTML, "- <b>%s</b> - ", pif->pstrTitle);
          }

          fprintf(fpHTML, "for at least %s\n", pstrTimeDown);
        }
      }
    }
  }

  if(fpHTML)
  {
    if(!nNumIfsDown)
    {
      fprintf(fpHTML, "there were no interfaces down.</h3>\n");
    }
    else
    {
      fprintf(fpHTML, "<p>Total of %d interfaces down.</p>\n", nNumIfsDown);
    }
    fprintf(fpHTML, "<br>\n<hr>\n<p><i>Page automatically generated by <a "
		    "href=\"http://www.nowthor.com/projects/frunk/\" target="
		    "\"_blank\">Frunk v%s</a></i></p>\n</body>\n</html>",
		    VERSION_FRUNKD);
    fclose(fpHTML);
    if(rename(DEFAULT_FRUNKD_NEW_HTML_OUTPUT_FILE,
              DEFAULT_FRUNKD_HTML_OUTPUT_FILE)<0)
    {
      Logf(FRUNK_LOG_ERR, "Could not rename '%s' to '%s', %s",
           DEFAULT_FRUNKD_NEW_HTML_OUTPUT_FILE,
           DEFAULT_FRUNKD_HTML_OUTPUT_FILE, strerror(errno));
    }
  }
}

